package app.wxchat;

import app.dtos.Shake;
import app.dtos.status.MemberStatus;
import app.events.EventBusContext;
import app.events.ImageDownloadEDto;
import app.models.member.Member;
import app.models.member.PhoneCollection;
import app.models.wx.Menu;
import app.models.wx.MessageSetting;
import app.models.wx.ReceiveMessage;
import app.models.wx.SendMessage;
import app.models.wx.VisitRecord;
import app.models.wx.VisitStat;
import com.github.sog.config.JFinalApp;
import com.github.sog.kit.encry.EncodeKit;
import com.github.sog.plugin.sqlinxml.SqlKit;
import com.github.sog.validator.ValidatorKit;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.jfinal.ext.kit.DateKit;
import com.jfinal.kit.PathKit;
import com.jfinal.module.wxchat.core.Constants;
import com.jfinal.module.wxchat.message.InputMessage;
import com.jfinal.module.wxchat.message.OutputMessage;
import com.jfinal.module.wxchat.message.input.EventInputMessage;
import com.jfinal.module.wxchat.message.input.TextInputMessage;
import com.jfinal.module.wxchat.message.output.TextOutputMessage;
import com.jfinal.module.wxchat.processor.MessageProcessor;
import com.jfinal.module.wxchat.utils.MessageUtil;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;
import java.util.Map;

/**
 * <p>
 *     微信消息处理接口
 * </p>
 *
 * @author Jerry Ou
 * @version 1.0 2014-02-12 13:41
 * @since JDK 1.6
 */
public class WxChatMessageProcessor extends MessageProcessor {
    private Logger logger = LoggerFactory.getLogger(WxChatMessageProcessor.class);

    private static final WxChatMessageProcessor instance = new WxChatMessageProcessor();
    private static final String extension = "wx_image";
    private static final String uploadroot = "/attachment/wx_image/";
    private static final String rootPath = PathKit.getWebRootPath();

    public static WxChatMessageProcessor getInstance() {
        return instance;
    }

    @Override
    public OutputMessage process(Map<String, String> message) {
        logger.debug(message.toString());
        OutputMessage outputMessage = null;

        InputMessage inputMessage = convertToMessage(message);
        String msgType = inputMessage.getMsgType();
        if (Constants.MSGTYPE_TEXT.equals(msgType)) { //文本消息，消息需要记录
            long id = saveReceiveMessage(msgType, message, false);
            outputMessage = processTextMessage((TextInputMessage) inputMessage);
            if (outputMessage != null) {
                saveSendMessage(outputMessage, id);
            }
        } else if (Constants.MSGTYPE_EVENT.equals(msgType)) { //事件消息，主要处理订阅，点击菜单，菜单视图事件
            outputMessage = processEventMessage((EventInputMessage) inputMessage, message);
        } else if (Constants.MSGTYPE_IMAGE.equals(msgType)) { //发送的图片消息，需要记录
            long id = saveReceiveMessage(msgType, message, true);
        }
        return outputMessage;
    }

    /**
     * 保存发送消息
     *
     * @param outputMessage 发送的消息
     * @param target 接收消息记录
     */
    private void saveSendMessage(OutputMessage outputMessage, long target) {
        String toUserName = outputMessage.getToUserName();
        //保存消息记录
        SendMessage sendMessage = new SendMessage();
        sendMessage.set("send_time", new Date());
        sendMessage.set("wx_account", toUserName);
        sendMessage.set("content", MessageUtil.outputMessageToXml(outputMessage));
        sendMessage.set("message_type", outputMessage.getMsgType());
        sendMessage.set("target", target);

        sendMessage.save();
    }

    /**
     * 保存接收消息记录
     *
     * @param msgType 接收消息类型
     * @param message 接收消息map数据
     * @param download 是否下载图片
     * @return 接收消息id
     */
    private long saveReceiveMessage(String msgType, Map<String, String> message, boolean download) {
        String fromUserName = message.get("FromUserName");
        long createTime = Long.parseLong(message.get("CreateTime"));
        Date time = messageCreateTimeParser(createTime);
        //保存消息记录
        ReceiveMessage receiveMessage = new ReceiveMessage();
        receiveMessage.set("recevie_time", time);
        receiveMessage.set("wx_account", fromUserName);
        receiveMessage.set("message_type", msgType);
        receiveMessage.set("content", mapToXml(message));
        receiveMessage.save();
        long id = receiveMessage.getNumber("id").longValue();

        if (download) { //执行异步下载
            Member member = Member.dao.findByWxNo(fromUserName);

            //String fileName = EncodeKit.toUUID() + StringPool.DOT + extension; //xxx.wx_image
            String fileName = EncodeKit.toUUID(); //xxx
            String savePath = uploadroot + fileName;
            String saveRealPath = rootPath + savePath;
            ImageDownloadEDto dto = new ImageDownloadEDto(fromUserName, member.getLong("id"), time, id, message.get("PicUrl"), savePath, saveRealPath, member.getInt("status"));
            EventBusContext.post(dto);
        }

        return id;
    }

    /**
     * 处理事件消息
     *
     * @param inputMessage 输入消息
     * @param message 消息map数据
     * @return 输出消息
     */
    private OutputMessage processEventMessage(EventInputMessage inputMessage, Map<String, String> message) {
        String event = inputMessage.getEvent();
        String fromUserName = inputMessage.getFromUserName();
        String toUserName = inputMessage.getToUserName();
        Member member = Member.dao.findFirst(SqlKit.sql("member.findByWxNo"), fromUserName);

        if (Constants.EVENT_SUBSCRIBE.equals(event)) { //订阅(关注)事件
            //生成临时会员
            if (member == null) {
                member = new Member();
                member.set("card_no", RandomStringUtils.randomNumeric(8));
                member.set("wx_no", fromUserName);
                member.set("currency", 0);
                member.set("integral", 0);
                member.set("temp", 1);
                member.set("update_time", new Date());
                member.save();
            }

            MessageSetting messageSetting = MessageSetting.dao.subscribe();
            if (messageSetting != null) {
                OutputMessage outputMessage = new WxChatMessageHelper().parseMessage(messageSetting, member);
                outputMessage.setFromUserName(toUserName);
                outputMessage.setToUserName(fromUserName);
                outputMessage.setCreateTime(milliStampToSecondStamp(System.currentTimeMillis()));
                return outputMessage;
            } else {
                TextOutputMessage.Builder builder = new TextOutputMessage.Builder(fromUserName, toUserName,
                        milliStampToSecondStamp(System.currentTimeMillis()), Constants.MSGTYPE_TEXT);
                builder.content("<a href=\""+ JFinalApp.domain +"\">中南城感谢您的关注，点击了解详情</a>");
                return builder.build();
            }
        } else if (Constants.EVENT_CLICK.equals(event)) { //菜单click
            //生成临时会员
            if (member == null) {
                member = new Member();
                member.set("card_no", RandomStringUtils.randomNumeric(8));
                member.set("wx_no", fromUserName);
                member.set("currency", 0);
                member.set("integral", 0);
                member.set("status", MemberStatus.HAS_CONCERNS); //设置已经关注
                member.set("temp", 1);
                member.set("update_time", new Date());
                member.save();
            }
            String eventKey = inputMessage.getEventKey();
            //记录模块访问日志
            Menu menu = Menu.dao.findByEvt(Constants.EVENT_CLICK.toLowerCase(), eventKey);
            visitRecord(inputMessage, menu);

            //生成回复消息
            //MessageSetting messageSetting = MessageSetting.dao.findClickMessage(eventKey);
            if (menu != null && !Strings.isNullOrEmpty(menu.getStr("json"))) {
                OutputMessage outputMessage = new WxChatMessageHelper().parseMenuMessage(menu, member);
                outputMessage.setFromUserName(toUserName);
                outputMessage.setToUserName(fromUserName);
                outputMessage.setCreateTime(milliStampToSecondStamp(System.currentTimeMillis()));
                return outputMessage;
            } else {
                TextOutputMessage.Builder builder = new TextOutputMessage.Builder(fromUserName, toUserName,
                        milliStampToSecondStamp(System.currentTimeMillis()), Constants.MSGTYPE_TEXT);
                builder.content("您好，您点击了：" + eventKey);
                return builder.build();
            }
        } else if (Constants.EVENT_VIEW.equals(event)) { //菜单view
            String eventKey = inputMessage.getEventKey();
            //记录模块访问日志
            Menu menu = Menu.dao.findByUrlPath(Constants.EVENT_VIEW.toLowerCase(), eventKey);
            visitRecord(inputMessage, menu);
            return null;
        }
        return null;
    }

    //记录模块访问日志
    private void visitRecord(EventInputMessage inputMessage, Menu menu) {
        if (menu != null) {
            VisitRecord visitRecord = new VisitRecord();
            Date d = messageCreateTimeParser(inputMessage.getCreateTime());
            visitRecord.set("visit_time", d);
            visitRecord.set("visit_date", d);
            visitRecord.set("create_time", new Date());
            int menuId = menu.getInt("id");
            String menuName = menu.getStr("name");
            visitRecord.set("visit_menu", menuId);
            visitRecord.save();

            //记录模块访问总计
            Date now = new Date();
            String today = DateFormatUtils.format(now, DateKit.dateFormat);
            VisitStat visitStat = VisitStat.dao.findByTodayAndMenu(today, menuId);
            if (visitStat == null) {
                visitStat = new VisitStat();
                visitStat.set("visit_module", menuId);
                visitStat.set("module_name", menuName);
                visitStat.set("stat_date", now);
                visitStat.set("visit_times", 1);
                visitStat.save();
            } else {
                long visit_times = visitStat.getLong("visit_times");
                visitStat.set("visit_module", menuId);
                visitStat.set("module_name", menuName);
                visitStat.set("stat_date", now);
                visitStat.set("visit_times", visit_times + 1);
                visitStat.update();
            }
        }
    }

    /**
     * 处理文本消息
     *
     * @param inputMessage 输入消息
     * @return 输出消息
     */
    private OutputMessage processTextMessage(TextInputMessage inputMessage) {
        String content = inputMessage.getContent();
        String toUserName = inputMessage.getToUserName();
        String fromUserName = inputMessage.getFromUserName();
        Member member = Member.dao.findFirst(SqlKit.sql("member.findByWxNo"), fromUserName);

        if (ValidatorKit.isMobile(content)) {

            PhoneCollection.dao.collection(content, fromUserName);

            MessageSetting messageSetting = MessageSetting.dao.findByKeyword("shake");
            if (Shake.me().map.get(content) != null) {
                content =  "手机号码："+ content +"已经输入过了";
                TextOutputMessage.Builder builder = new TextOutputMessage.Builder(inputMessage.getFromUserName(), inputMessage.getToUserName(), System.currentTimeMillis(), Constants.MSGTYPE_TEXT);
                builder.content(content);
                return builder.build();
            }
            if (messageSetting != null) {
                WxChatMessageHelper helper = new WxChatMessageHelper();
                Map<String, Object> map = Maps.newHashMap();
                map.put("_phone_", content);
                OutputMessage message = helper.parseMessageWithParamVals(messageSetting, member, map);
                message.setFromUserName(toUserName);
                message.setToUserName(fromUserName);
                message.setCreateTime(milliStampToSecondStamp(System.currentTimeMillis()));

                return message;
            }
            return null;
        } else {
            MessageSetting messageSetting = MessageSetting.dao.findByKeyword(content);
            if (messageSetting != null) {
                WxChatMessageHelper helper = new WxChatMessageHelper();
                Map<String, Object> map = Maps.newHashMap();
                map.put("_mid_", member.get("id"));
                map.put("_wxno_", member.getStr("wx_no"));
                OutputMessage message = helper.parseMessageWithParamVals(messageSetting, member, map);
                message.setFromUserName(toUserName);
                message.setToUserName(fromUserName);
                message.setCreateTime(milliStampToSecondStamp(System.currentTimeMillis()));
                return message;
            }
            return null;
        }
    }

}
